﻿using InquiroSample.Common;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

using Windows.Storage;
using OrandoLabs.Common;
using OrandoLabs.Inquiro;
using OrandoLabs.Inquiro.EsentApi;
using OrandoLabs.Inquiro.Parsers;
using System.Threading.Tasks;

// The Grid App template is documented at http://go.microsoft.com/fwlink/?LinkId=234226

namespace InquiroSample
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        OrandoInstance Instance;
        InquiroInstance IInstance;
        InquiroDatabase Database;
        Exception InquiroException;
        String InquiroDirName = "inquiro-dir";
        String InquiroInstanceName = "inquiro";
        String InquiroDatabaseName = "inquiro1.edb";

        private async Task<bool> InitializeInquiroAsync()
        {
            InquiroException = null;
            var appData = Windows.Storage.ApplicationData.Current;
            var path = appData.LocalFolder.CreateFolderAsync(InquiroDirName, CreationCollisionOption.OpenIfExists);
            var folder = await path.AsTask<Windows.Storage.StorageFolder>();
            var baseDir = folder.Path;

            return await Task.Run(() =>
            {
                bool inner = true;
                try
                {
                    Instance = new OrandoInstance(InquiroInstanceName, baseDir);
                    EsentId InstanceId = InstanceIdWrapper.GetInstanceId(Instance);
                    IInstance = new InquiroInstance(baseDir, InstanceId);
                    Database = new InquiroDatabase(IInstance, InquiroDatabaseName);
                    EsentApi api = new EsentApi();
                    OrandoLabs.Inquiro.Api.SetApi(api);
                }
                catch (Exception e)
                {
                    inner = false;
                    InquiroException = e;
                }
                return inner;
            }
            );
        }

        private async Task<bool> TerminateInquiroAsync()
        {
            return await Task.Run(() =>
            {
                if (Instance != null)
                {
                    Instance.Dispose();
                    Instance = null;
                }
                return true;
            }
            );
        }

        private async Task<bool> LoadInquiroAsync()
        {
            return await Task<bool>.Run(() =>
                {
                    string[] documents = new string[] { Document1, Document2, Document3 };
                    InquiroTextTokenizer parser = new InquiroTextTokenizer();

                    using (InquiroContext ctx = new InquiroContext(Database, "inquirotest"))
                    {
                        // Check to see if data was loaded already
                        TextTerm term = new TextTerm("microsoft", new Target(1), 0);
                        List<Term> result = ctx.FindTerms(term);
                        if (result.Count == 0)
                        {
                            for (int i = 0; i < documents.Length; i++)
                            {
                                parser.Parse(documents[i]);
                                Target target = new Target((i + 1));
                                parser.Compile(target);
                                ctx.AddTermsForTarget(parser.Terms.ToArray());
                            }
                        }
                    }
                    return true;
                }
            );
        }

        private async Task<bool> TryInquiroQueryAsync()
        {
            return await Task<bool>.Run(() =>
            {
                using (InquiroContext ctx = new InquiroContext(Database, "inquirotest"))
                {
                    TextTerm term = new TextTerm("microsoft", new Target(1), 0);
                    List<Term> result = ctx.FindTerms(term);
                    if (result.Count != 3) return false;

                    InquiroSearchParser search = new InquiroSearchParser(Kinds.Dictionary);
                    TermResult termresult = search.Search("\"need a graphics adapter\"", ctx);
                    if (termresult.Count != 3) return false;
                    termresult = search.Search("windows", ctx);
                    if (termresult.Count != 3) return false;
                }
                return true;
            }
            );
        }

        /// <summary>
        /// Initializes the singleton Application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used when the application is launched to open a specific file, to display
        /// search results, and so forth.
        /// </summary>
        /// <param name="args">Details about the launch request and process.</param>
        protected override async void OnLaunched(LaunchActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();
                //Associate the frame with a SuspensionManager key                                
                SuspensionManager.RegisterFrame(rootFrame, "AppFrame");

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    // Restore the saved session state only when appropriate
                    try
                    {
                        await SuspensionManager.RestoreAsync();
                    }
                    catch (SuspensionManagerException)
                    {
                        //Something went wrong restoring state.
                        //Assume there is no state and continue
                    }
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }
            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                if (!rootFrame.Navigate(typeof(GroupedItemsPage), "AllGroups"))
                {
                    throw new Exception("Failed to create initial page");
                }
            }

            if (Instance == null)
            {
                bool success = await InitializeInquiroAsync();
                if (!success)
                {
                    // Inquiro initialization failed, look in InquiroException for more information
                }
                else
                {
                    await LoadInquiroAsync();
                    await TryInquiroQueryAsync();
                }
            }

            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            await SuspensionManager.SaveAsync();
            await TerminateInquiroAsync();
            deferral.Complete();
        }

        static string Document1 = @"
We've all waited a long time for 
these: Microsoft Windows 2.03 
for the 8088 and 80286 CPUs 
and Windows/386 for the 80386 
CPU. The first version of Windows was slow; it did not support 
concurrency, nor did it directly use more than 640K bytes of 
memory. It also required more complex 
software development with limited 
choices of development language (mainly 
a Microsoft C toolbox). 

Version 2.03 ($99) is faster than the 
original Windows product and makes the 
best of microcomputers without the 
80386 chips. The 386 version ($195) offers 
true multitasking, thanks to the power of 
the 80386. Microsoft claims that both of 
these versions strongly resemble the Presentation Manager of OS/2. There are 
many aspects that are common between 
Windows 2.03 and Windows/386, and if 
you learn to use one, you can (to a good 
extent) utilize the other version. 

The Windows 2.03 environment runs 
on the IBM PC, XT, AT, PS/2s, or compatibles. It runs under DOS 3.0 or higher 
and requires 512K bytes of memory, and 
you can use any additional memory (ex- 
panded or extended) with the SMART-Drive disk cache to enhance the system 
speed. You will need up to 2 megabytes of 
hard disk space to copy files from the 
seven 360K-byte distribution disks. You 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 

The Windows/386 environment requires you to have an 80386 CPU, with 1 
(preferably 2 or more) megabytes of 
memory, including extended or ex- 
panded memory. A high-density floppy 
disk drive is required to read the three 
distribution disks of this version, while 2 
megabytes of hard disk space are needed 
to store Windows files. Windows/386 
runs under DOS 3.1 or higher. You will 
also need a graphics adapter compatible 
with CGA, EGA, or VGA. For both versions, a mouse is optional. You might 
find that building reflexes for the combination keys works better. 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 

The setup of Windows 2.03 is easy and 
straightforward. A SETUP.EXE utility 
guides you to select the various machine, 
printer, display, and mouse options. I 
was able to run Windows 2.03 without 
modifying my CONFIG.SYS or AUTO- 
EXEC.BAT files. For this review, I installed Windows 2.03 in my second 
(card-type) hard disk and was able to run 
it successfully. I could not do the same 
with Windows/386, however. I had to install that version on my main hard disk, 
and I could not access the second hard 
disk. You can use the AUTOEXEC.BAT (or a 
specialized batch file), or you can issue a 
normal DOS command to invoke Windows 2.03. 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 

The setup of Windows/386 is similar to 
that of Windows 2.03: You need to remove any RAM-resident pop-up utilities, 
such as SideKick and SuperKey. To use 
Windows/386, you have to create new 
CONFIG.SYS and AUTOEXEC.BAT files. If 
you plan to use Windows/386 consistently, you must make the changes to the 
files in the main hard disk directory. The 
other alternative, which I used for this review, is to prepare a separate boot disk, 
which should contain new versions of 
CONFIG.SYS and AUTOEXEC.BAT. The 
CONFIG.SYS files should not install the 
usual RAM-disk drive. Instead, you may 
install the Windows SMARTDrive disk 
cache. The AUTOEXEC.BAT should not 
install any RAM-resident pop-up utilities, since Windows/386 can easily and 
intelligently manage them. You can use 
the AUTOEXEC.BAT file to invoke 
Windows/386. 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 
            ";
        static string Document2 = @"
The Windows environment uses the 
text file WIN. INI to store various system 
parameters and special instructions. You 
can edit this file to fine-tune the parameters or alter the special instruc- 
tions. The WIN. INI file represents a new variation of the 
combined AUTOEXEC.BAT and 
CONFIG.SYS files in DOS. 
Among the interesting options 
is the list of ""load"" and ""run"" 
programs. Whenever you load Windows, 
the applications shown in the load list 
automatically load and display as icons. 
Similarly, the run list names the applications that automatically execute when you 
load Windows. The programs list defines 
the program file-extension names. This 
list is set to EXE, COM, and BAT, and the 
MS-DOS Executive window uses it to 
select program files for the directory 
display. The WIN. INI file enables you to 
specify numerous parameters, such as 
spooling status, printer selection, font selection, I/O port selection, and beeping 
status. I look forward to seeing future 
DOS versions support a file similar to 
WIN. INI. 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 

If you are afraid of corrupting the 
WIN. INI file with your text editor, Windows has another, more formal, route. 
You can alter many of these parameters 
by accessing the control panel, which is a 
window with menus that permits you to 
add or delete fonts and printers, alter 
window colors, change communication 
ports and data transfer rates, and so on. 

The MS-DOS Executive 

When you invoke either Windows version, the MS-DOS Executive windows 
appear. In general, there are three display 
levels for any windows application: full 
screen, window, or icon. Only Windows/386 is able to support these three 
levels of display for standard programs 
(i.e., those not designed as Windows-oriented applications). An application in 
either full- screen or window display uses 
the upper screen line to display the control-menu box, a title bar, and the maximize/minimize boxes. The latter boxes 
permit you to go between a full screen, a 
window, and an icon display. 
            ";
        static string Document3 = @"
Windows applications use the second 
line to display their menu bars. You can 
use a mouse or key combinations to access the boxes in the top line or the menu 
options in the second line. The control 
box of any application enables you to 
manipulate the related window in the following ways: move, resize, manipulate 
the display status (e.g., maximize or minimize the window), close, or restore. At 
that point, the window displays any 
option that is not available to you by using 
blurred characters or faded colors. With 
Windows applications, you can use the 
close command to end the applications. 
With standard applications, you need to 
exit them using their own particular 
commands first, and then close their 
windows. 
will also need a graphics adapter compatible with CGA, EGA, Hercules, or VGA. 

The MS-DOS Executive window is the 
launching point for many applications. It 
displays the names of the files and subdirectories of the current directory. 
Subdirectory names are displayed first in bold 
characters, and the list of sorted filenames is shown in normal characters. 
The Executive window also displays the 
current file or subdirectory selection in 
reverse video. Since you do not have access to a command-line processor, you 
must perform everything using pull-down 
menus. The MS-DOS Executive windows have three menu options: file, view, 
and special. The file menu offers you the 
ability to perform a number of internal 
DOS commands, such as rename, copy, 
and delete files, as well as load and run 
programs. These options work on the 
currently selected file. 

Among the interesting features that I 
found in the MS-DOS Executive is that 
you can mark multiple files for collective 
copying or deletion. A File command 
lets you load an application and its related 
data file by simply loading the latter (this 
is similar to how the Apple Macintosh 
works). For example, if you load a text 
file created by the Window word processor WRITE.EXE, you create a special icon. 
When you click on the icon, you find 

yourself in a word-processing session 
with the text file being displayed. 

The view menu enables you to view 
files in either a short format (just the filename) or a long format that includes file 
size and date/time stamps. You can also 
elect to display all or some of the files, or 
just programs. The MS-DOS Executive 
displays the filenames sorted by name, 
date, size, or time. The ""special"" menu 
offers more important commands that 
you would generally use less frequently. 
These options permit you to create a directory, change the current directory, 
format a disk, create a system disk, and 
set the volume name. 
";


    }
}
